package cn.jiangjiesheng.bootstrap.cloud.service.metadata;

import cn.hutool.core.util.RuntimeUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Created by dev@jiangjiesheng.cn on 2022/11/2  <br/>
 *
 * @author dev@jiangjiesheng.cn
 */
@Data
@Accessors(chain = true)
public class MetadataSingleton {

    private static volatile MetadataSingleton instance;

    private Integer pid;
    private Double freeMemory;
    private Double totalMemory;
    private Integer availableProcessors;
    private String processName;
    private String workDir;
    private String javaHome;
    private String processInfo;

    private String jarFile;
    private String osName;

    private Map<String, String> nacosInfo = Maps.newHashMap();

    /**
     * 关联的数据源信息
     */
    private Map<String, String> jdbcUrls;

    public static synchronized MetadataSingleton getInstance() {
        if (Objects.isNull(instance)) {
            synchronized (MetadataSingleton.class) {
                if (Objects.isNull(instance)) {
                    instance = new MetadataSingleton();
                } else {
                    return instance;
                }
            }
        }
        return instance;
    }

    private MetadataSingleton() {
        this.setPid(RuntimeUtil.getPid())
                .setFreeMemory(Runtime.getRuntime().freeMemory() / 1024D / 1024D)
                .setTotalMemory(Runtime.getRuntime().totalMemory() / 1024D / 1024D)
                .setAvailableProcessors(Runtime.getRuntime().availableProcessors())
                .setProcessName(ManagementFactory.getRuntimeMXBean().getName())
                .setWorkDir(System.getProperty("user.dir"))
                .setOsName(System.getProperty("os.name"))
                .setJavaHome(System.getProperty("java.home"));
        if (this.isUnixLikeOs()) {
            final Process exec;
            try {
                exec = Runtime.getRuntime().exec("/bin/sh -c 'ps aux | grep'" + this.getPid());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            final InputStream outputStream = exec.getInputStream();
            final List<String> strings;
            try {
                exec.waitFor(100, TimeUnit.MILLISECONDS);
                strings = IOUtils.readLines(outputStream, StandardCharsets.UTF_8);
            } catch (InterruptedException | IOException e) {
                throw new RuntimeException(e);
            }
            this.setProcessInfo(Joiner.on("\n").join(strings.stream()
                    .filter(e -> !e.contains("TIME") && e.contains(".jar"))
                    .collect(Collectors.toList())));
            Pattern pattern = null;
            Matcher matcher = null;
            pattern = Pattern.compile("java -jar .*?([a-zA-Z0-9-_.]+.jar)");
            matcher = pattern.matcher(this.getProcessInfo());
            if(matcher.find()){
                this.setJarFile(matcher.toMatchResult().group(1));
            }
        } else {
            this.setProcessInfo("Only supported for unix-like os.");
        }

    }

    private Boolean isUnixLikeOs() {
        return StringUtils.containsAnyIgnoreCase(osName, "Mac", "Linux");
    }
}
